<script setup lang="ts">
import { onMounted } from 'vue'
// 1. 导入three.js
import * as THREE from 'three'
// draco decoder
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
// GLTF loader
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'

import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

// 相机，场景，渲染器
let camera: THREE.Camera
let scene: THREE.Scene
let renderer: THREE.WebGLRenderer
let controls: OrbitControls
let grid: THREE.GridHelper
let wheels: THREE.Object3D[] = []
function init() {
  const container = document.getElementById('container')
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0x333333)

  camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.1, 100)
  camera.position.set(4.25, 1.4, -4.5)

  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setAnimationLoop(render)
  container?.appendChild(renderer.domElement)

  // 轨道
  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  controls.maxDistance = 9
  controls.target.set(0, 0.5, 0)
  controls.update()

  // GridHelper
  grid = new THREE.GridHelper(20, 40, 0xffffff, 0xffffff)
  grid.material.opacity = 0.2
  grid.material.depthWrite = false
  grid.material.transparent = true
  scene.add(grid)

  // 环境贴图
  scene.environment = new RGBELoader().load(new URL(`./assets/car/venice_sunset_1k.hdr`, import.meta.url).href)
  scene.environment.mapping = THREE.EquirectangularReflectionMapping

  // 材质
  const bodyMaterial = new THREE.MeshPhysicalMaterial({
    color: 0xff0000,
    metalness: 1.0,
    roughness: 0.5,
    clearcoat: 1.0,
    clearcoatRoughness: 0.03,
    sheen: 0.5,
  })
  const wheelMaterial = new THREE.MeshStandardMaterial({
    color: 0xffffff,
    metalness: 1.0,
    roughness: 0.5,
  })
  const glassMaterial = new THREE.MeshPhysicalMaterial({
    color: 0xffffff,
    metalness: 0.5,
    roughness: 0,
    transmission: 1.0,
  })
  // 修改色值
  document.getElementById('body-color')?.addEventListener('input', (e) => {
    bodyMaterial.color.set((e.target as HTMLInputElement).value)
  })
  document.getElementById('wheel-color')?.addEventListener('input', (e) => {
    wheelMaterial.color.set((e.target as HTMLInputElement).value)
  })
  document.getElementById('glass-color')?.addEventListener('input', (e) => {
    glassMaterial.color.set((e.target as HTMLInputElement).value)
  })

  // 阴影
  const shadow = new THREE.TextureLoader().load(new URL(`./assets/car/ferrari_ao.png`, import.meta.url).href)

  // 3D模型加载
  const dracoLoader = new DRACOLoader()
  dracoLoader.setDecoderPath('decoder/')

  const gltfLoader = new GLTFLoader()
  gltfLoader.setDRACOLoader(dracoLoader)

  const glb = new URL(`./assets/car/ferrari.glb`, import.meta.url).href
  gltfLoader.load(glb, (gltf) => {
    const carModel = gltf.scene.children[0]
    const body = carModel.getObjectByName('body') as THREE.Mesh
    body.material = bodyMaterial
    const rim_fl = carModel.getObjectByName('rim_fl') as THREE.Mesh
    rim_fl.material = wheelMaterial
    const rim_fr = carModel.getObjectByName('rim_fr') as THREE.Mesh
    rim_fr.material = wheelMaterial
    const rim_rl = carModel.getObjectByName('rim_rl') as THREE.Mesh
    rim_rl.material = wheelMaterial
    const rim_rr = carModel.getObjectByName('rim_rr') as THREE.Mesh
    rim_rr.material = wheelMaterial
    const glass = carModel.getObjectByName('glass') as THREE.Mesh
    glass.material = glassMaterial
    const wheel_fl = carModel.getObjectByName("wheel_fl")
    if (wheel_fl) {
      wheels.push(wheel_fl)
    }
    const wheel_fr = carModel.getObjectByName("wheel_fr")
    if (wheel_fr) {
      wheels.push(wheel_fr)
    }
    const wheel_rl = carModel.getObjectByName("wheel_rl")
    if (wheel_rl) {
      wheels.push(wheel_rl)
    }
    const wheel_rr = carModel.getObjectByName("wheel_rr")
    if (wheel_rr) {
      wheels.push(wheel_rr)
    }

    // 阴影配置
    const mesh = new THREE.Mesh(
      new THREE.PlaneGeometry(0.655*4, 1.3*4), 
      new THREE.MeshBasicMaterial({ 
        map: shadow,
        blending: THREE.MultiplyBlending,
      })
    )
    mesh.rotation.x = -Math.PI / 2
    mesh.renderOrder = 2
    carModel.add(mesh)
    
    scene.add(carModel)
  }) 
}

function render() {
  controls.update()

  const time = performance.now() / 1000
  grid.position.z = time % 1

  wheels.forEach((wheel) => {
    wheel.rotation.x = -time * Math.PI * 2
  })

  renderer.render(scene, camera)
}

onMounted(() => {
  init()
})
</script>

<template>
  <div>
    <div id="info">
      <h2>请确保你的浏览器支持 WebGL，可以点击
        <a href="https://get.webgl.org/">这里</a>
        进行检测。如果不支持，请自行解决。
      </h2>
      <span class="colorPicker">
        <input type="color" id="body-color" value="#ff0000" />
        <br />
        车身
      </span>
      <span class="colorPicker">
        <input type="color" id="wheel-color" value="#ffffff" />
        <br />
        轮毂
      </span>
      <span class="colorPicker">
        <input type="color" id="glass-color" value="#ffffff" />
        <br />
        玻璃
      </span>
    </div>
    <!-- 渲染汽车 -->
     <div id="container"></div>
  </div>

</template>

<style>
body {
  color: #bbbbbb;
  background: #333333;
  text-align: center;
  overflow: hidden;
}

a {
  color: #08f;
}

.colorPicker {
  display: inline-block;
  margin: 0 10px;
}
</style>
